using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

using Microsoft.Xna.Framework;

namespace Xfinity.Entities
{
    /// <summary>
    /// A generic entity.
    /// </summary>
    [Serializable]
    public abstract class Entity : DrawableGameComponent
    {
        /// <summary>
        /// Called when the entity is initializing.
        /// </summary>
        public static event EventHandler Created;
        private string name;

        /// <summary>
        /// The name of this entity.
        /// </summary>
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        /// <summary>
        /// Constructs a new entity.
        /// </summary>
        /// <param name="name">The name for this entity.</param>
        /// <param name="game">The main Game object.</param>
        protected Entity(string name, Game game)
            : base(game)
        {
            Enabled = false;
            this.name = name;
            Visible = false;
        }
        /// <summary>
        /// Constructs a new entity.
        /// </summary>
        /// <param name="game">The main Game object.</param>
        protected Entity(Game game)
            : base(game)
        {
            Enabled = false;
            name = GetType().FullName;
            Visible = false;
        }
        /// <summary>
        /// Initialises the entity.
        /// </summary>
        public override void Initialize()
        {
            if (Created != null)
            {
                Created(this, EventArgs.Empty);
            }
            Trace.WriteLine(name + " initialising.", "Init");
            base.Initialize();
        }
        public override void Update(GameTime gameTime)
        {
            LogUpdate();
            base.Update(gameTime);
        }
        #region Debugging
        private static bool debugging;

        /// <summary>
        /// Debugging.
        /// </summary>
        public static bool IsDebugging()
        {
            return debugging;
        }
        [Conditional("DEBUG")]
        public static void SetDebugging(bool debug)
        {
            debugging = debug;
        }

        #endregion
        [Conditional("DEBUG")]
        private void LogUpdate()
        {
            if (debugging)
            {
                System.Diagnostics.Debug.WriteLine(Name + " updating.");
            }

        }
#if !XBOX
        /// <summary>
        /// Serializes the entity.
        /// </summary>
        /// <param name="filename">The file to the serialized object to.</param>
        public void Serialize(string filename)
        {
            System.Diagnostics.Debug.WriteLine(name + " serializing.", "Serializing");
            using (XmlTextWriter s = new XmlTextWriter(filename, Encoding.UTF8))
            {
                s.Formatting = Formatting.Indented;

                s.WriteStartDocument();
                s.WriteStartElement("XnaContent");
                s.WriteStartElement("Asset");
                s.WriteAttributeString("Type", GetType().FullName);

                XmlSerializer serializer = new XmlSerializer(GetType());
                using (StringWriter sw = new StringWriter())
                {
                    serializer.Serialize(sw, this);
                    sw.Flush();

                    XmlDocument d = new XmlDocument();
                    d.LoadXml(sw.GetStringBuilder().ToString());

                    foreach (XmlNode node in d.DocumentElement.ChildNodes)
                    {
                        s.WriteNode(node.CreateNavigator(), true);
                    }
                }
                s.WriteEndDocument();

            }
            System.Diagnostics.Debug.WriteLine(name + " serialized sucessfully.", "Serialized");

        }

        /// <summary>
        /// Deserialize the object.
        /// </summary>
        /// <param name="filename">The file to read from.</param>
        public void Deserialize(string filename)
        {
            using (XmlTextReader s = new XmlTextReader(filename))
            {
                s.ReadToDescendant("Asset");

                string type = s.GetAttribute("Type");


                string inner = s.ReadInnerXml();


                XmlSerializer serializer = new XmlSerializer(GetType());
                StringWriter sw = new StringWriter();

                XmlTextWriter w = new XmlTextWriter(sw);
                string[] names = type.Split('.');
                type = names[names.Length - 1];
                w.WriteStartElement(type);

                w.WriteRaw(inner);
                w.WriteEndElement();
                w.Flush();
                System.Diagnostics.Debug.Assert(sw.GetStringBuilder().ToString() != null);


                object temp = serializer.Deserialize(new StringReader(sw.GetStringBuilder().ToString()));
                foreach (PropertyInfo p in GetType().GetProperties())
                {

                    PropertyInfo pi = GetType().GetProperty(p.Name);

                    try
                    {
                        object handle;
                        handle = pi.GetValue(temp, null);
                        p.SetValue(this, handle, null);

                    }
                    catch (ArgumentException)
                    {
                        continue;
                    }
                }

            }
        }
#endif
    }

}